const {
    BollStatus,
    // StoreName,
    OrderDirection,
    XFactorOpen,
    XFactorNomal
} = require('./../constants')
const Decimal = require('decimal.js')
// const LogService = require('./LogService')

class BollService {
    getCurrentStatus ({bollList, minBollWidth, klineList, price, isJudgeWidthIncrease}) {
        // 根据布林线判断出目前是震荡、收窄、还是单边
        const {
            upper: bollUp,
            middle: bollMiddle,
            // lower: bollDown
        } = bollList[bollList.length - 1]

        if (Decimal(bollUp).sub(bollMiddle).toNumber() < minBollWidth) {
            // 收窄行情
            return BollStatus.NARROW
        } else {
            /* 思路：获取到收窄过后的列表，判断方向；如果有传过布林中轨，说明回到震荡 */
            const listIndexAfterLastNarrow = this.getIndexAfterLastNarrow(bollList, klineList, minBollWidth, isJudgeWidthIncrease)
            if (!listIndexAfterLastNarrow) {
                return BollStatus.SHAKE
            } else {
                const recentBollList = bollList.slice(listIndexAfterLastNarrow)
                const recentKlineList = klineList.slice(listIndexAfterLastNarrow)
                return this._getBollOneSideStatus(recentBollList, recentKlineList, price)
            }
        }
    }
    getIndexAfterLastNarrow (bollList, klineList, minBollWidth, isJudgeWidthIncrease = true) {
        let lastNarrowIndex = 0
        let lastEnlargeIndex = 0
        let lastCrossIndex = 0
        for(let index = 0; index < bollList.length - 1; index++) {
            const item = bollList[index]
            const kItem = klineList[index]
            const {
                upper: bollUp,
                middle: bollMiddle,
                // lower: bollDown
            } = item
            const currentBollWidth = Decimal(bollUp).sub(bollMiddle).toNumber()

            // 价格穿过中轨
            if (kItem.lowestPrice < bollMiddle && kItem.highestPrice > bollMiddle) {
                lastCrossIndex = index
            }

            if (currentBollWidth < minBollWidth) {
                // 小于最小半径，为窄
                lastNarrowIndex = index
            } else if (index > 1 && isJudgeWidthIncrease) {
                const {
                    upper,
                    middle
                } = bollList[index - 1]
                const lastBollWidth = upper - middle
                const kLastItem = klineList[index - 1]
                const {
                    upper: upper2,
                    middle: middle2
                } = bollList[index - 2]
                const last2BollWidth = upper2 - middle2
                // 最近两根加起来扩大有30%，为窄
                if (
                    currentBollWidth > lastBollWidth &&
                    lastBollWidth > last2BollWidth &&
                    currentBollWidth < 400 &&
                    (kItem.volumn + kLastItem.volumn) > 250 &&
                    (
                        Decimal(currentBollWidth).div(last2BollWidth).toNumber() > 1.3 ||
                        Decimal(currentBollWidth).div(lastBollWidth).toNumber() > 1.2
                    )
                ) {
                    // 计算开始扩大的那一项，
                    if (lastEnlargeIndex && lastEnlargeIndex > lastCrossIndex) {
                        // 布林线开始扩大位置已经记录，且开始扩大的位置，在越过布林中线之后，则不用修改
                    } else {
                        // 否则，记录当前布林线扩大位置
                        lastEnlargeIndex = index
                    }
                }
            }
        }
        return Math.max(lastNarrowIndex, lastEnlargeIndex)
    }
    getShakeOpenOrderDirection (price, bollList, ratio = 0) {
        const {
            upper: bollUp,
            middle: bollMiddle
        } = bollList[bollList.length - 1]
        const bollWidth = Decimal(bollUp).sub(bollMiddle).toNumber()
        let shakeOpenDirection = null
        if (price > (bollMiddle + bollWidth * ratio)) {
            shakeOpenDirection  = OrderDirection.SELL
        }
        if (price < (bollMiddle - bollWidth * ratio)) {
            shakeOpenDirection  = OrderDirection.BUY
        }
        return shakeOpenDirection
    }
    _getBollOneSideStatus (bollList, klineList, price) {
        const _1stMiddle = bollList[0].middle
        const _lastMiddle = bollList[bollList.length - 1].middle
        let status = BollStatus.SHAKE
        if (_lastMiddle > _1stMiddle) {
            status = BollStatus.ONESIDEUP
        } else {
            status = BollStatus.ONESIDEDOWN
        }
        let isPriceCross = false
        klineList.slice(2).forEach((item, index) => {
            switch (status) {
                case BollStatus.ONESIDEUP:
                    if (item.lowestPrice < bollList[index + 2].middle || price < bollList[index + 2].middle) {
                        isPriceCross = true
                    }
                    break;
            
                case BollStatus.ONESIDEDOWN:
                    if (item.highestPrice > bollList[index + 2].middle || price > bollList[index + 2].middle) {
                        isPriceCross = true
                    }
                    break;
            
                default:
                    break;
            }
        })

        if (isPriceCross) status = BollStatus.SHAKE
        return status
    }
    getNarrowOpenDirection (bollList, price) {
        const parseBollList = bollList.slice(-4).map(item => ({
            bollWidth: item.upper - item.middle,
            bollUp: item.upper,
            bollDown: item.lower
        }))
        const [_0, _1, _2, _3] = parseBollList
        // 符合以下两个条件，可以开窄边单
        let direction = ''
        let reason = ''
        // 1. 穿出布林线
        if (price > _3.bollUp) direction = OrderDirection.SELL
        if (price < _3.bollDown) direction = OrderDirection.BUY
        if (!direction) reason = '在布林线内运行'
        // 2. 布林半径没有明显变大趋势
        if (
            (_3.bollWidth - _2.bollWidth) < 13 &&
            (_2.bollWidth - _1.bollWidth) < 13
            // (_1.bollWidth - _0.bollWidth) < 5
        ) {
            reason = direction ? '最近3根布林线宽度变化小于10' : '没有穿出布林线'
        } else {
            reason = '布林线宽度在逐渐变大'
            direction = ''
        }

        // 太小
        if (_3.bollWidth < 80) {
            direction = ''
            reason = '布林带太窄，没有盈利空间，不做'
        }

        return [direction, reason]
    }
    getDirectDesc (direction) {
        return direction === OrderDirection.SELL ? '空' : '多'
    }
    /**
     * 通过计算前两个布林段的偏移，得出下一个合适开单位置
     * @param {Array} bollList 布林列表
     * @param {String} direction 开单方向
     */
    getShakeXFactor (bollList, direction, currentBollStatus) {
        if (currentBollStatus === BollStatus.SHAKE) return 1
        const [_1, _2, _3] = bollList.slice(-3)
        const {
            upper: bollUp1,
            lower: bollDown1
        } = _1
        const {
            upper: bollUp2,
            lower: bollDown2
        } = _2
        const {
            upper: bollUp3,
            lower: bollDown3
        } = _3
        let xFactor = undefined
        switch (direction) {
            case OrderDirection.BUY:
                if (
                    bollDown2 > bollDown3
                ) {
                    if (
                        bollDown1 > bollDown2 &&
                        ((bollDown1 - bollDown2) < (bollDown2 - bollDown3))
                    ) {
                        // 布林线口袋开口变大
                        xFactor = (bollDown1 - bollDown3) * XFactorOpen
                    } else {
                        // 布林线口袋开口没有变大
                        xFactor = (bollDown2 - bollDown3) * XFactorNomal
                    }
                }
                break;
            case OrderDirection.SELL:
                if (
                    bollUp2 < bollUp3
                ) {
                    if (
                        bollUp1 < bollUp2 &&
                        ((bollUp2 - bollUp1) < (bollUp3 - bollUp2))
                    ) {
                        // 布林线口袋开口变大
                        xFactor = (bollUp3 - bollUp1) * XFactorOpen
                    } else {
                        // 布林线口袋开口没有变大
                        xFactor = (bollUp3 - bollUp2) * XFactorNomal
                    }
                }
                break;
            default:
                break;
        }
        return xFactor
    }
}

module.exports = new BollService()